#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <cstring>
#include <memory>
#include "Logger.hpp"
#include "Common.hpp"
#include "Protocol.hpp"
#include "Caculate.hpp"

using namespace LogMudule;

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " ip port" << std::endl;
        return 1;
    }
    std::string ip = argv[1];
    u_int16_t port = std::stoi(argv[2]);

    // 创建套接字
    int cilentsockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cilentsockfd < 0)
    {
        LOG(LogLevel::FATAL) << "socket error!";
        return 2;
    }

    // 服务器地址
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(port);
    serveraddr.sin_addr.s_addr = inet_addr(ip.c_str());

    // 连接服务器
    int n = ::connect(cilentsockfd, Conv(&serveraddr), sizeof(serveraddr));
    if (n < 0)
    {
        LOG(LogLevel::FATAL) << "connect error!";
        return 3;
    }
    std::string message;
    while (true)
    {
        // 读取信息
        char inbuffer[1024];
        int a, b;
        char op;
        std::cout << "请输入计算式: ";
        std::cin >> a >> op >> b;
        Request request(a, b, op);
        // 序列化
        request.Serialize(message);
        // 编码
        Encode(message);
        // 发送信息
        int n = ::send(cilentsockfd, message.c_str(), message.size(), 0);
        if (n > 0)
        {
            // 写入信息
            int n = ::recv(cilentsockfd, inbuffer, sizeof(inbuffer), 0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                int result;
                int code;
                std::string content;
                std::string package = inbuffer;
                // 解码
                Decode(package, &content);
                // 反序列化
                Response response;
                response.Deserialize(content);
                result = response.Result();
                code = response.Code();
                std::cout << result << "[" << code << "]" << std::endl;
            }

            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "server close!";
                close(cilentsockfd);
                break;
            }
            else
            {
                LOG(LogLevel::ERROR) << "read error!";
                close(cilentsockfd);
                break;
            }
        }
        else break;
    }
    ::close(cilentsockfd);

    return 0;
}
